#include <string.h>
#include <stdio.h>
#include "CRC.h"
#define printf_debug	printf
/* 参考链接: https://blog.csdn.net/u013073067/article/details/86621770 */

const CRC8_StructTypedef crc_8 					= {0x07,0x00,0x00,false,false};
const CRC8_StructTypedef crc_8_ITU 				= {0x07,0x00,0x55,false,false};
const CRC8_StructTypedef crc_8_ROHC 			= {0x07,0xff,0x00,true,true};
const CRC8_StructTypedef crc_8_MAXIM 			= {0x31,0x00,0x00,true,true};

const CRC16_StructTypedef crc_16_IBM 			= {0x8005,0x0000,0x0000,true,true};
const CRC16_StructTypedef crc_16_MAXIM 			= {0x8005,0x0000,0xffff,true,true};
const CRC16_StructTypedef crc_16_USB 			= {0x8005,0xffff,0xffff,true,true};
const CRC16_StructTypedef crc_16_MODBUS 		= {0x8005,0xffff,0x0000,true,true};
const CRC16_StructTypedef crc_16_CCITT 			= {0x1021,0x0000,0x0000,true,true};
const CRC16_StructTypedef crc_16_CCITT_FALSE 	= {0x1021,0xffff,0x0000,false,false};
const CRC16_StructTypedef crc_16_X5 			= {0x1021,0xffff,0xffff,true,true};
const CRC16_StructTypedef crc_16_XMODEM 		= {0x1021,0x0000,0x0000,false,false};
const CRC16_StructTypedef crc_16_DNP 			= {0x3d65,0x0000,0xffff,true,true};

const CRC32_StructTypedef crc_32 				= {0x04c11db7,0xffffffff,0xffffffff,true,true};
const CRC32_StructTypedef crc_32_MPEG2 			= {0x04c11db7,0xffffffff,0x00000000,false,false};

uint8_t reverse8(uint8_t data); 
uint16_t reverse16(uint16_t data);
uint32_t reverse32(uint32_t data); 
void printf_bin8(uint8_t data);
void printf_bin16(uint16_t data);
void printf_bin32(uint32_t data);

/*单字节反转*/
uint8_t reverse8(uint8_t data)
{

    uint8_t i;
//    printf_debug(data);
//    printf_debug("\n");
    uint8_t temp=0;
    for(i=0;i<8;i++)		//反转
    {
        	if(data & (0x01<<i))
        	{
        		temp |= 0x01<<(7-i);
			}
		}
//    printf_debug(temp);
//    printf_debug("\n");
    return temp;
}

/*双字节反转*/
uint16_t reverse16(uint16_t data)
{

    uint8_t i;
//    printf_debug(data);
//    printf_debug("\n");
    uint16_t temp=0;
    for(i=0;i<16;i++)		//反转
        {
        	if(data & (0x01<<i))
        	{
        		temp |= 0x01<<(15-i);
			}
		}
//    printf_debug(temp);
//    printf_debug("\n");
    return temp;
}

/*四字节反转*/
uint32_t reverse32(uint32_t data)
{

    uint8_t i;
//    printf_debug(data);
//    printf_debug("\n");
    uint32_t temp=0;
    for(i=0;i<32;i++)		//反转
    {
        	if(data & (0x01<<i))
        	{
        		temp |= 0x01<<(31-i);
			}
		}
//    printf_debug(temp);
//    printf_debug("\n");
    return temp;
}
/**
 * @brief   8位CRC校验
 * 
 * @param   CRC_Struct  CRC算法类型
 * @param   data        指向数据的指针
 * @param   sizeOfData         数据的长度(单位：字节)
 * @return  uint8_t 	8位CRC校验值
 */
uint8_t CRC8Check(const CRC8_StructTypedef* CRC_Struct, const uint8_t* data,size_t sizeOfData)
{
	uint8_t temp = 0;
	uint8_t CRC_VALUE = CRC_Struct->INIT ;
	for(uint32_t i = 0;i < sizeOfData;i++)
	{
        temp = data[i];
		if(CRC_Struct->REFIN == true)//判断是否输入反转
		{
			temp = reverse8(temp);//输入反转
		}
//		printf_debug("\n%d",temp);
		CRC_VALUE ^=  (temp); //与crc初始值异或
//		printf_debug("\n%d",CRC_VALUE);
        for(int j = 0;j<8;j++) 
		{
			if(CRC_VALUE & (0x01<<7))//判断最高位是否为1
			{
				CRC_VALUE <<= 1;
				CRC_VALUE ^= CRC_Struct->POLY  ;
			}
            else
			{
				CRC_VALUE <<= 1;
			}
		}
	}
    //	printf_debug("\n%d",CRC_VALUE);
	if(CRC_Struct->REFOUT == true)//输出是否需要反转
	{
		CRC_VALUE = reverse8(CRC_VALUE);
	}
	CRC_VALUE ^= CRC_Struct->XOROUT;//与结果异或值异或
	return  CRC_VALUE;
}

/**
 * @brief   16位CRC校验
 * 
 * @param   CRC_Struct  CRC算法类型
 * @param   data        指向数据的指针
 * @param   sizeOfData         数据的长度(单位：字节)
 * @return  uint16_t 	16位CRC校验值
 */
uint16_t CRC16Check(const CRC16_StructTypedef* CRC_Struct, const uint8_t* data,size_t sizeOfData)
{
	uint8_t temp = 0;
	uint16_t CRC_VALUE = CRC_Struct->INIT ;
	for(uint32_t i = 0;i < sizeOfData;i++)
	{
        temp = data[i];
		if(CRC_Struct->REFIN == true)//判断是否输入反转
		{
			temp = reverse8(temp);//输入反转
		}
//		printf_debug("\n%d",temp);
		CRC_VALUE ^=  (temp<<8);//CRC高8位异或，低8位数据不变
//		printf_debug("\n%d",CRC_VALUE);
        for(int j = 0;j<8;j++) 
		{
			if(CRC_VALUE & (0x01<<15))//判断最高位是否为1
			{
				CRC_VALUE <<= 1;
				CRC_VALUE ^= CRC_Struct->POLY  ;
			}
            else
			{
				CRC_VALUE <<= 1;
			}
		}
	}
    //	printf_debug("\n%d",CRC_VALUE);
	if(CRC_Struct->REFOUT == true)//输出是否需要反转
	{
		CRC_VALUE = reverse16(CRC_VALUE);
	}
	CRC_VALUE ^= CRC_Struct->XOROUT;//与结果异或值异或
	return  CRC_VALUE;
}

/**
 * @brief   32位CRC校验
 * 
 * @param   CRC_Struct  CRC算法类型
 * @param   data        指向数据的指针
 * @param   sizeOfData  数据的长度(单位：字节)
 * @return  uint32_t 	32位CRC校验值
 */
uint32_t CRC32Check(const CRC32_StructTypedef* CRC_Struct, const uint8_t* data,size_t sizeOfData)
{
	uint8_t temp = 0;
	uint32_t CRC_VALUE = CRC_Struct->INIT ;
	for(uint32_t i = 0;i < sizeOfData;i++)
	{
        temp = data[i];
		if(CRC_Struct->REFIN == true)//判断是否输入反转
		{
			temp = reverse8(temp);//输入反转
		}
//		printf_debug("\n%d",temp);
		CRC_VALUE ^=  (temp<<24);//与crc初始值高8位异或
//		printf_debug("\n%d",CRC_VALUE);
        for(int j = 0;j<8;j++) 
		{
			if(CRC_VALUE & (0x01<<31))//判断最高位是否为1
			{
				CRC_VALUE <<= 1;
				CRC_VALUE ^= CRC_Struct->POLY  ;
			}
            else
			{
				CRC_VALUE <<= 1;
			}
		}
	}
    //	printf_debug("\n%d",CRC_VALUE);
	if(CRC_Struct->REFOUT == true)//输出是否需要反转
	{
		CRC_VALUE = reverse32(CRC_VALUE);
	}
	CRC_VALUE ^= CRC_Struct->XOROUT;//与结果异或值异或
	return  CRC_VALUE;
}
/**
 * @brief   计算crc值
 * 
 * @param   CRC_Struct  crc算法类型
 * @param   data        指向数据的指针
 * @param   sizeOfData  数据的长度(单位：字节)
 * @param   rec_buf     用于接收crc值
 * @param   sizeOf_CRC_Struct	crc算法类型结构体的大小(单位字节)
 * @return  其它 		产生的CRC字节长度
 * @return  0 		参数错误
 */
uint8_t crcCheck(const void* CRC_Struct, const uint8_t* data,size_t sizeOfData,void *rec_buf,size_t sizeOf_CRC_Struct)
{
	if(CRC_Struct == NULL || data == NULL || rec_buf == NULL)
		return 0;

	if(sizeOf_CRC_Struct == sizeof(CRC8_StructTypedef))
	{
		uint8_t  crc = CRC8Check((CRC8_StructTypedef*)CRC_Struct,data,sizeOfData);
		memcpy(rec_buf,&crc,sizeof(crc));
		return 1;
	}
	else if(sizeOf_CRC_Struct == sizeof(CRC16_StructTypedef))
	{
		uint16_t crc = CRC16Check((CRC16_StructTypedef*)CRC_Struct,data,sizeOfData);
		memcpy(rec_buf,&crc,sizeof(crc));
		return 2;
	}
	else if(sizeOf_CRC_Struct == sizeof(CRC32_StructTypedef))
	{
		uint32_t crc = CRC32Check((CRC32_StructTypedef*)CRC_Struct,data,sizeOfData);
		memcpy(rec_buf,&crc,sizeof(crc));
		return 4;
	}
	return 0;
}

void printf_bin8(uint8_t data)
{
	for(int i = 0;i<8;i++)
	{
		if(data & (0x01<<(7-i)))
		printf_debug("1");
		else
		printf_debug("0");
	}
	printf_debug("\n");
}

void printf_bin16(uint16_t data)
{
	for(int i = 0;i<16;i++)
	{
		if(data & (0x01<<(15-i)))
		printf_debug("1");
		else
		printf_debug("0");
	}
	printf_debug("\n");
}

void printf_bin32(uint32_t data)
{
	for(int i = 0;i<32;i++)
	{
		if(data & (0x01<<(31-i)))
		printf_debug("1");
		else
		printf_debug("0");
	}
	printf_debug("\n");
}